/**
* @file    winmodule.h
* @brief   ...
* @author  bbcallen
* @date    2009-02-25  11:08
*/

#ifndef WINMODULE_H
#define WINMODULE_H

#include <atlbase.h>
namespace Utils
{

	class CWinModule
	{
	public:
		CWinModule();

		CWinModule(CWinModule& h);

		explicit CWinModule(HMODULE h);

		virtual ~CWinModule();

		virtual void FreeLib();




		operator HMODULE() const;

		void    Attach(HMODULE h);

		HMODULE Detach();

		HRESULT LoadLib(LPCWSTR lpDllPath);

		HRESULT LoadLibEx(LPCWSTR lpDllPath, DWORD dwFlag);

		FARPROC GetProcAddr(LPCSTR lpProcName);

		BOOL    IsValid();

		HRESULT HresultFromLastError();

	private:
		// disabled
		CWinModule& operator=(CWinModule& h);

	private:
		HMODULE m_hLib;
	};



	inline CWinModule::CWinModule(): m_hLib(NULL)
	{

	}

	inline CWinModule::CWinModule(HMODULE h)
	{
		if (m_hLib != h)
		{
			FreeLib();
			m_hLib = h;
		}
	}

	inline CWinModule::~CWinModule()
	{
		FreeLib();
	}

	inline void CWinModule::FreeLib()
	{
		if (m_hLib)
		{
			::FreeLibrary(m_hLib);
			m_hLib = NULL;
		}
	}

	inline CWinModule::operator HMODULE() const
	{
		return m_hLib;
	}

	inline void CWinModule::Attach(HMODULE h)
	{
		FreeLib();
		m_hLib = h;
	}

	inline HMODULE CWinModule::Detach()
	{
		HMODULE hLib = m_hLib;
		m_hLib = NULL;
		return hLib;
	}

	inline HRESULT CWinModule::LoadLib(LPCWSTR lpDllPath)
	{
		HMODULE hLib = ::LoadLibrary(lpDllPath);
		if (!hLib)
		{
			return GetLastError() ? AtlHresultFromLastError() : E_FAIL;
		}

		FreeLib();
		m_hLib = hLib;
		return S_OK;
	}

	inline HRESULT CWinModule::LoadLibEx(LPCWSTR lpDllPath, DWORD dwFlag)
	{
		HMODULE hLib = ::LoadLibraryEx(lpDllPath, NULL, dwFlag);
		if (!hLib)
		{
			return GetLastError() ? AtlHresultFromLastError() : E_FAIL;
		}

		FreeLib();
		m_hLib = hLib;
		return S_OK;
	}

	inline FARPROC CWinModule::GetProcAddr(LPCSTR lpProcName)
	{
		if (!m_hLib)
			return NULL;

		return ::GetProcAddress(m_hLib, lpProcName);
	}

	inline BOOL CWinModule::IsValid()
	{
		return NULL != m_hLib;
	}
}
#endif//WINMODULE_H

